#ifndef __HTTP_CONNECTION_H__
#define __HTTP_CONNECTION_H__

#include "stream/socket_stream.h"
#include "http.h"
#include "uri.h"
#include "thread.h"

#include "http_parser.h"
#include "log.h"
#include "stream/zlib_stream.h"

#include <list>

namespace johnsonli
{
namespace http
{

    /**
     * @brief HTTP响应结果
     */
    struct HttpResult {
        /// 智能指针类型定义
        typedef std::shared_ptr<HttpResult> ptr;
        /**
         * @brief 错误码定义
         */
        enum class Error {
            /// 正常
            OK = 0,
            /// 非法URL
            INVALID_URL = 1,
            /// 无法解析HOST
            INVALID_HOST = 2,
            /// 连接失败
            CONNECT_FAIL = 3,
            /// 连接被对端关闭
            SEND_CLOSE_BY_PEER = 4,
            /// 发送请求产生Socket错误
            SEND_SOCKET_ERROR = 5,
            /// 超时
            TIMEOUT = 6,
            /// 创建Socket失败
            CREATE_SOCKET_ERROR = 7,
            /// 从连接池中取连接失败
            POOL_GET_CONNECTION = 8,
            /// 无效的连接
            POOL_INVALID_CONNECTION = 9,
        };

        /**
         * @brief 构造函数
         * @param[in] _result 错误码
         * @param[in] _response HTTP响应结构体
         * @param[in] _error 错误描述
         */
        HttpResult(int _result
                ,HttpResponse::ptr _response
                ,const std::string& _error)
            :result(_result)
            ,response(_response)
            ,error(_error) {}

        /// 错误码
        int result;
        /// HTTP响应结构体
        HttpResponse::ptr response;
        /// 错误描述
        std::string error;

        std::string toString() const;
    };

    class HHttpConnectionPool;

    class HttpConnection : public SocketStream
    {
    public:
        typedef std::shared_ptr<HttpConnection> ptr;
        /**
         * @brief 构造函数
         * @param[in] sock Socket类
         * @param[in] owner 是否掌握所有权
         */
        HttpConnection(Socket::ptr sock, bool owner = true);

        ~HttpConnection();

         /**
         * @brief 发送HTTP的GET请求
         * @param[in] url 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoGet(const std::string& url
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP的GET请求
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoGet(Uri::ptr uri
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP的POST请求
         * @param[in] url 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoPost(const std::string& url
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP的POST请求
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoPost(Uri::ptr uri
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP请求
         * @param[in] method 请求类型
         * @param[in] uri 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoRequest(HttpMethod method
                                , const std::string& url
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP请求
         * @param[in] method 请求类型
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoRequest(HttpMethod method
                                , Uri::ptr uri
                                , uint64_t timeout_ms
                                , bool is_close = true
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");


        /**
         * @brief 接收HTTP响应
         */
        HttpResponse::ptr recvResponse();

        /**
         * @brief 发送HTTP请求
         * @param[in] req HTTP请求结构
         */
        int sendRequest(HttpRequest::ptr req);

        uint64_t getCreateTime() { return m_createTime; }
        void setCreateTime(uint64_t v) { m_createTime = v; }

        uint64_t getRequestCount() { return m_requestCount; }
        void setRequestCount(uint64_t v) { m_requestCount = v; }

    private:
        /**
         * @brief 发送HTTP请求
         * @param[in] req 请求结构体
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] is_close 是否自动关闭
         * @return 返回HTTP结果结构体
         */
        static HttpResult::ptr DoRequest(HttpRequest::ptr req
                                , Uri::ptr uri
                                , uint64_t timeout_ms
                                , bool is_close = true);

    private:
        uint64_t m_createTime = 0;          // 创建时间
        uint64_t m_requestCount = 0;        // 发起连接请求的数量
    };

    class HttpConnectionPool 
    {
    public:
        typedef std::shared_ptr<HttpConnectionPool> ptr;
        typedef Mutex MutexType;

        static HttpConnectionPool::ptr Create(const std::string& uri
                                        ,const std::string& vhost
                                        ,uint32_t max_size
                                        ,uint32_t max_alive_time
                                        ,uint32_t max_request);

        HttpConnectionPool(const std::string& host
                            ,const std::string& vhost
                            ,uint32_t port
                            ,bool is_https
                            ,uint32_t max_size
                            ,uint32_t max_alive_time
                            ,uint32_t max_request);

        HttpConnection::ptr getConnection();

        /**
         * @brief 发送HTTP的GET请求
         * @param[in] url 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doGet(const std::string& url
                            , uint64_t timeout_ms
                            , const std::map<std::string, std::string>& headers = {}
                            , const std::string& body = "");

        /**
         * @brief 发送HTTP的GET请求
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doGet(Uri::ptr uri
                            , uint64_t timeout_ms
                            , const std::map<std::string, std::string>& headers = {}
                            , const std::string& body = "");

        /**
         * @brief 发送HTTP的POST请求
         * @param[in] url 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doPost(const std::string& url
                            , uint64_t timeout_ms
                            , const std::map<std::string, std::string>& headers = {}
                            , const std::string& body = "");

        /**
         * @brief 发送HTTP的POST请求
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doPost(Uri::ptr uri
                            , uint64_t timeout_ms
                            , const std::map<std::string, std::string>& headers = {}
                            , const std::string& body = "");

        /**
         * @brief 发送HTTP请求
         * @param[in] method 请求类型
         * @param[in] uri 请求的url
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doRequest(HttpMethod method
                                , const std::string& url
                                , uint64_t timeout_ms
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP请求
         * @param[in] method 请求类型
         * @param[in] uri URI结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @param[in] headers HTTP请求头部参数
         * @param[in] body 请求消息体
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doRequest(HttpMethod method
                                , Uri::ptr uri
                                , uint64_t timeout_ms
                                , const std::map<std::string, std::string>& headers = {}
                                , const std::string& body = "");

        /**
         * @brief 发送HTTP请求
         * @param[in] req 请求结构体
         * @param[in] timeout_ms 超时时间(毫秒)
         * @return 返回HTTP结果结构体
         */
        HttpResult::ptr doRequest(HttpRequest::ptr req
                                , uint64_t timeout_ms);
    private:
        static void ReleasePtr(HttpConnection* ptr, HttpConnectionPool* pool);    
        

    private:
        std::string m_host;             // host
        std::string m_vhost;            // vhost
        uint32_t m_port;                // port
        uint32_t m_maxSize;             // 连接池最大数量
        uint32_t m_maxAliveTime;        // 连接池连接最大存活时间
        uint32_t m_maxRequest;          // 每个连接最大请求次数
        bool m_isHttps;

        MutexType m_mutex;
        std::list<HttpConnection*> m_conns;     // 连接池
        std::atomic<int32_t> m_total = {0};     // 连接池中总的连接数量
    };
}
}

#endif